package com.ea.framework.interceptor;


import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.common.framework.web.response.ResultModel;
import com.ea.api.vo.UserInfoVO;
import com.ea.framework.session.SessionUtil;
import com.ea.repository.entity.SysUser;
import com.ea.repository.mapper.SysUserMapper;
import com.ea.util.JwtUtils;
import com.ea.util.RedisUtils;
import com.ea.util.StringUtil;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 权限(Token)验证
 */
@Component
public class AuthorizationInterceptor extends HandlerInterceptorAdapter {
	@Autowired
	private SysUserMapper sysUserMapper;
	@Autowired
	private RedisUtils redisUtils;

	public static final String USER_KEY = "userId";
	private static final Set<String> NOT_AUTH_URL = new HashSet<String>();

	static {
		NOT_AUTH_URL.add(".*/openapi/.*");
		NOT_AUTH_URL.add(".*/open/.*");
		NOT_AUTH_URL.add(".*/statics/html/.*");
		NOT_AUTH_URL.add(".*/crm/login.htm$");
		NOT_AUTH_URL.add(".*/crm/loginAction$");
		NOT_AUTH_URL.add(".*/login$");
		NOT_AUTH_URL.add(".*/app/user/registerUser$");
		NOT_AUTH_URL.add(".*/app/user/appWxUserLogIn$");
		NOT_AUTH_URL.add(".*/app/user/xcxUserLogIn$");
		NOT_AUTH_URL.add(".*/app/system/uploadFile$");
		NOT_AUTH_URL.add(".*/app/system/uploadAppPackage$");
		NOT_AUTH_URL.add(".*/app/uploadFile$");
		NOT_AUTH_URL.add(".*/NewFile.jsp$");
		NOT_AUTH_URL.add(".*/swagger-resources$");
		NOT_AUTH_URL.add(".*/*.no$");
		NOT_AUTH_URL.add(".*/*.html$");
		NOT_AUTH_URL.add(".*/*.css$");
		NOT_AUTH_URL.add(".*/*.js$");
		NOT_AUTH_URL.add(".*/*.jsp$");
	}

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		if("OPTIONS".equals(request.getMethod())) {
			return true;
		}
		SessionUtil.clear();
		if(request.getRequestURI().endsWith("/error")) {
			buildResponse(response, ResultModel.CODE_FAILURE, "路径不存在或系统错误");
			return false;
		}
		// 获取用户凭证
		String token = request.getHeader(JwtUtils.HEADER);
		if (StringUtil.isBlank(token)) {
			/**请求头header中如果没有token参数，则再去param请求参数中获取**/
			token = request.getParameter(JwtUtils.HEADER);
		}
		// 不需要验证的请求
		if(("null".equals(token) || StringUtil.isEmpty(token)) && !isAuth(request)) {
			return true;
		}
		// 凭证为空
		if (StringUtil.isBlank(token)) {
			buildResponse(response, ResultModel.TOKEN_TIMEOUT, JwtUtils.HEADER + "不能为空");
			return false;
		}
		// 获取token中的用户名，根据token信息解密
		Claims claims = JwtUtils.getClaimByToken(token);
		if (claims == null || JwtUtils.isTokenExpired(claims.getExpiration())) {
			buildResponse(response, ResultModel.TOKEN_TIMEOUT, JwtUtils.HEADER + "失效，请重新登录");
			return false;
		}
		// 设置userId到request里，后续根据userId，获取用户信息
		String subject = claims.getSubject();
		if(subject != null && subject.length() > 0) {
			UserInfoVO appUserVo = new UserInfoVO();
			UserInfoVO userVo = (UserInfoVO) redisUtils.get(token);
			if (null == userVo) {
				SysUser sysUser = sysUserMapper.selectById(subject.split("_")[1]);
				if (sysUser != null) {
					BeanUtil.copyProperties(sysUser, appUserVo);
					redisUtils.set(token, appUserVo, 60L, TimeUnit.MINUTES);
				} else {
					buildResponse(response, ResultModel.TOKEN_TIMEOUT, "非法访问");
				}
			}else{
				appUserVo = userVo;
			}
			SessionUtil.putAppUser(appUserVo);
			return true;
		}
		buildResponse(response, ResultModel.TOKEN_TIMEOUT, "非法访问");
		return false;
	}

	/**
	 * 判断当前请求是否需要验证回话
	 *
	 * @param request
	 * @return
	 */
	private static boolean isAuth(HttpServletRequest request) {
		String reqUrl = request.getRequestURI();
		Iterator<String> notAuthUrlIt = NOT_AUTH_URL.iterator();
		while (notAuthUrlIt.hasNext()) {
			Pattern pattern = Pattern.compile(notAuthUrlIt.next());
			Matcher matcher = pattern.matcher(reqUrl);
			if (matcher.matches()) {
				return false;
			}
		}
		return true;
	}

	/**
	 * 构建返回值
	 * @param response
	 * @param code
	 * @param msg
	 */
	public static void buildResponse(HttpServletResponse response, Integer code, String msg) {
		response.setStatus(HttpStatus.OK.value());
	    response.setHeader("Cache-Control", "no-cache, must-revalidate");
	    response.setCharacterEncoding("UTF-8");
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        try {
            response.getWriter().write(JSON.toJSONString(ResultModel.fail(code, msg)));
        } catch (IOException e) {
        	e.printStackTrace();
        }
	}
}
